Curso de Python para Ingenieros Mecánicos

Por: Eduardo Vieira



Uso de widgets interactivos en Jupyter


Después de haber aprendido a utilizar las bibliotecas de Python científico claves (NumPy, matplotlib y SymPy), con los módulos interactivos de IPython / Jupyter podemos obtener resultados interactivas de muy alta calidad y altamente personalizables.

La función interactive (IPython.html.widgets.interact) crea automáticamente y con un comando una interfaz gráfica de usuario (GUI) para la exploración de código y datos de forma interactiva. Es la forma más fácil de comenzar a utilizar los widgets de IPython.

Este notebook es una traducción parcial de un tutorial de Jupyter dado por sus desarroladores durante la Strata Silicon Valley 2015. Vamos a empezar por lo más sencillo.

En primer lugar, importamos los módulos que vamos a utilizar:


In [2]:
from __future__ import print_function
from IPython.html.widgets import interact, interactive, fixed
from IPython.html import widgets


/home/eduardo/anaconda3/lib/python3.6/site-packages/IPython/html.py:14: ShimWarning: The `IPython.html` package has been deprecated since IPython 4.0. You should import from `notebook` instead. `IPython.html.widgets` has moved to `ipywidgets`.
  "`IPython.html.widgets` has moved to `ipywidgets`.", ShimWarning)

Uso básico de interact

At the most basic level, interact autogenerates UI controls for function arguments, and then calls the function with those arguments when you manipulate the controls interactively. To use interact, you need to define a function that you want to explore. Here is a function that prints its only argument x.

A nivel más básico, interact genera controles automáticamente mediante una interfaz gráfica de usuario para los argumentos de una función que debe ser definida previamente. Así, interact llama a dicha función con los argumentos que se definieron para manipularlos con controles de forma interactiva.

Por tanto, para utilizar interact, es necesario definir la función en Python que desea explorar. Vamos a crear es una función que imprime su único argumento x:


In [3]:
def f(x):
    print(x)

When you pass this function as the first argument to interact along with an integer keyword argument (x=10), a slider is generated and bound to the function.

Ahora utilizaremos esta función como primer argumento para interact junto con un argumento predifinido a un entero (x = 10), se autogenera un control deslizante (slider) y con que nos permite interactuar con esta función.


In [4]:
interact(f, x=10);


Al mover el deslizador, se llama a la función y el valor actual de x se imprime.

Si hacemos pasar un True o False, interact generará una casilla de verificación:


In [5]:
interact(f, x=True);


Si hacemos pasar una cadena de texto (string), interact generará un campo de texto:


In [6]:
interact(f, x=u'¡Hola!');


Fijando argumentos usando fixed

Hay momentos en los que es posible que vayamos a explorar una función utilizando interact, pero queramos fijar una o más de sus argumentos a valores específicos. Esto puede lograrse haciendo uso la función fixed.


In [7]:
def h(p, q):
    print(p, q)

Cuando llamamos a interact, hacemos pasar fixed(20) para mantener q fijado al valor de 20.


In [8]:
interact(h, p=5, q=fixed(20));


Fijate que el deslizador solo responde a p y que el valor de q está fijado con el valor 20.

Widget abbreviation

Cuando pasamos un entero como argumento (x=10) a interact, se genera un deslizador de valores enteros con el rango de $[-10,+3\times10]$. En este caso, 10 es una abreviación de un widget slider tipo:

IntSliderWidget(min=-10,max=30,step=1,value=10)

De hecho, podemos obtener el mismo resultado si pasamos este IntSliderWidget como el argumento de palabra clave para x:


In [10]:
interact(f, x=widgets.IntSlider(min=-10,max=30,step=1,value=10));


Este ejemplo aclara como interactuar con con procesos mediante sus argumentos clave:

  1. Si el argumento clave es Widget con un atributo tipo value, se utiliza el widget tipo slider. Cualquier widget con un atributo que resulte en un valor numérico se puede utilizar, incluso los personalizados.
  2. De lo contrario, el valor se trata como una widget abbreviation que se convierte en un widget antes de su uso.

La siguiente tabla ofrece una visión general de los diferentes widget abbreviation:

Keyword argumentWidget
`True` or `False`CheckboxWidget
`'Hola'`TextareaWidget
`value` or `(min,max)` or `(min,max,step)` if integers are passedIntSliderWidget
`value` or `(min,max)` or `(min,max,step)` if floats are passedFloatSliderWidget
`('naranja','manzana')` or `{'uno':1,'dos':2}`Dropdown

Hemos visto arriba cómo funcionan los widgets checkbox y de área de texto. Veamos, más detalles sobre las diferentes abreviaturas para deslizadores y menús desplegables.

Si se pasa un tupla con dos enteros (min, max) un deslizador con valores también enteros se crea utilizando los mismos como máximo y mínimo. En este caso, se utiliza el tamaño de paso predeterminado de 1.


In [11]:
interact(f, x=(0,4));


Si se pasa un tupla con tres enteros (min,max,step), lo que hacemos es determinar también el tamaño de paso:


In [12]:
interact(f, x=(0,8,2));


Para que el widget devuelva valores en coma flotante, debemos pasar una tupla con valores en coma flotante. En el siguiente ejemplo, el mínimo es 0.0, el máximo es 10.0 y el intervalo es de 0.1 (por defecto).


In [13]:
interact(f, x=(0.0,10.0));


De nuevo, el tamaño del intervalo se puede determinar haciendo uso de un tercer elemento en la tupla:


In [14]:
interact(f, x=(0.0,10.0,0.01));


Para ambos sliders de enteros y flotantes, se puede escoger el valor inicial del widget pasando un argumento de palabra clave por defecto a la función Python subyacente. Aquí establecemos el valor inicial de un slider con valores en coma flotante a 5.5.


In [15]:
def h(x=5.5):
    print(x)
    
interact(h, x=(0.0,20.0,0.5));


También podemos crear menús desplegables haciendo pasar una tupla de cadenas de texto (strings). En este caso, las cadenas de texto son utilizados como los nombres de la interfaz de usuario del menú desplegable y pasan a la función Python subyacente.


In [18]:
interact(f, x=['manzanas','naranjas']);


Si quieres un menú desplegable que pasa valores que no son cadenas de texto a la función de Python, se puede pasar un diccionario. Las palabras claves del diccionario se utilizan para los nombres de la interfaz de usuario del menú desplegable y los valores son los argumentos que se pasan a la función Python subyacente. Se puede entender mejor viendo este ejemplo:


In [19]:
interact(f, x={'uno': 10, 'dos': 20});


Widgets interactivos y Matplotlib

Como ya sabes, IPython de maravilla con Matplotlib. Veamos cómo podemos combinar los widgets interactivos con esta bibliote gráfica.

Repaso: creando un gráfico

A modo de repaso, veamos cómo creabamos un gráfico simple. Primero debemos de cargar las bibliotecas:


In [20]:
from __future__ import print_function
from IPython.html.widgets import interact, interactive, fixed

import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline

# Vamos a cambiar el estilo por defecto (opcional)
plt.style.use('ggplot')

In [21]:
# Creamos un array con valores de x
x = np.linspace(0, 3*np.pi, 500)
y = np.sin(x**2)

plt.plot(x, y)
plt.title(u'Un gráfico simple');


Haciendo un gráfico interactivo

En el siguiente ejemplo, una función que representa gráficamente la suma de dos ondas sinusoidales la combinamos con interact.


In [22]:
def dibuja_ondas(frequencia1, frequencia2):
    x = np.linspace(0, 3*np.pi, 500)
    y = np.sin(x*frequencia1) + np.sin(x*frequencia2)
    plt.plot(x,y)
    
    plt.title(u'¡Mira mamá, gráficos interactivos!')
    
interact( dibuja_ondas, frequencia1=20., frequencia2=21.)


Out[22]:
<function __main__.dibuja_ondas>

Referencias


In [23]:
# Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = './css/aeropython.css'
HTML(open(css_file, "r").read())


Out[23]:
/* This template is inspired in the one used by Lorena Barba in the numerical-mooc repository: https://github.com/numerical-mooc/numerical-mooc We thank her work and hope you also enjoy the look of the notobooks with this style */ El estilo se ha aplicado =)

In [ ]: